package com.android.fxcontacts.model;

import java.io.IOException;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import com.android.fxcontacts.R;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
import android.util.Xml;

/**
 * Internal structure that represents constraints and styles for a specific data
 * source, such as the various data types they support, including details on how
 * those types should be rendered and edited.
 * <p>
 * In the future this may be inflated from XML defined by a data source.
 */
public class ExternalSource extends FallbackSource
{
	private static final String ACTION_SYNC_ADAPTER = "android.content.SyncAdapter";
	private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE";

	private interface InflateTags
	{
		final String CONTACTS_SOURCE = "ContactsSource";
		final String CONTACTS_DATA_KIND = "ContactsDataKind";
	}

	public ExternalSource(String resPackageName)
	{
		this.resPackageName = resPackageName;
		this.summaryResPackageName = resPackageName;
	}

	/**
	 * Ensure that the constraint rules behind this {@link ContactsSource} have
	 * been inflated. Because this may involve parsing meta-data from
	 * {@link PackageManager}, it shouldn't be called from a UI thread.
	 */
	@Override
	public void inflate(Context context, int inflateLevel)
	{
		// Handle unknown sources by searching their package
		final PackageManager pm = context.getPackageManager();
		final Intent syncAdapter = new Intent(ACTION_SYNC_ADAPTER);
		final List<ResolveInfo> matches = pm.queryIntentServices(syncAdapter,
				PackageManager.GET_META_DATA);
		for (ResolveInfo info : matches)
		{
			final XmlResourceParser parser = info.serviceInfo.loadXmlMetaData(
					pm, METADATA_CONTACTS);
			if (parser == null)
				continue;
			inflate(context, parser);
		}

		// Bring in name and photo from fallback source, which are non-optional
		inflateStructuredName(context, inflateLevel);
		inflatePhoto(context, inflateLevel);

		setInflatedLevel(inflateLevel);
	}

	/**
	 * Inflate this {@link ContactsSource} from the given parser. This may only
	 * load details matching the publicly-defined schema.
	 */
	protected void inflate(Context context, XmlPullParser parser)
	{
		final AttributeSet attrs = Xml.asAttributeSet(parser);

		try
		{
			int type;
			while ((type = parser.next()) != XmlPullParser.START_TAG
					&& type != XmlPullParser.END_DOCUMENT)
			{
				// Drain comments and whitespace
			}

			if (type != XmlPullParser.START_TAG)
			{
				throw new IllegalStateException("No start tag found");
			}

			if (!InflateTags.CONTACTS_SOURCE.equals(parser.getName()))
			{
				throw new IllegalStateException("Top level element must be "
						+ InflateTags.CONTACTS_SOURCE);
			}

			// Parse all children kinds
			final int depth = parser.getDepth();
			while (((type = parser.next()) != XmlPullParser.END_TAG || parser
					.getDepth() > depth)
					&& type != XmlPullParser.END_DOCUMENT)
			{
				if (type == XmlPullParser.END_TAG
						|| !InflateTags.CONTACTS_DATA_KIND.equals(parser
								.getName()))
				{
					continue;
				}

				final TypedArray a = context.obtainStyledAttributes(attrs,
						R.styleable.ContactsDataKind);
				final DataKind kind = new DataKind();

				kind.mimeType = a
						.getString(R.styleable.ContactsDataKind_mimeType1);
				kind.iconRes = a.getResourceId(
						R.styleable.ContactsDataKind_icon1, -1);

				final String summaryColumn = a
						.getString(R.styleable.ContactsDataKind_summaryColumn1);
				if (summaryColumn != null)
				{
					// Inflate a specific column as summary when requested
					kind.actionHeader = new FallbackSource.SimpleInflater(
							summaryColumn);
				}

				final String detailColumn = a
						.getString(R.styleable.ContactsDataKind_detailColumn1);
				final boolean detailSocialSummary = a
						.getBoolean(
								R.styleable.ContactsDataKind_detailSocialSummary,
								false);

				if (detailSocialSummary)
				{
					// Inflate social summary when requested
					kind.actionBodySocial = true;
				}

				if (detailColumn != null)
				{
					// Inflate specific column as summary
					kind.actionBody = new FallbackSource.SimpleInflater(
							detailColumn);
				}

				addKind(kind);
			}
		} catch (XmlPullParserException e)
		{
			throw new IllegalStateException("Problem reading XML", e);
		} catch (IOException e)
		{
			throw new IllegalStateException("Problem reading XML", e);
		}
	}

	@Override
	public int getHeaderColor(Context context)
	{
		return 0xff6d86b4;
	}

	@Override
	public int getSideBarColor(Context context)
	{
		return 0xff6d86b4;
	}
}
